#include "m2716.h"
#include <stdint.h>
#include "stm32f1xx_hal_gpio.h" // Add this include for GPIOA, GPIOB, GPIOC definitions

void M_Delay_us(uint32_t udelay)
{
  uint32_t startval,tickn,delays,wait;
 
  startval = SysTick->VAL;
  tickn = HAL_GetTick();
//  //sysc = 72000;  //SystemCoreClock / (1000U / uwTickFreq);
//  delays =udelay * 72; //sysc / 1000 * udelay;
	delays =udelay * 180; //sysc / 1000 * udelay;
  if(delays > startval)
	{
		while(HAL_GetTick() == tickn)
		{

		}
		wait = 180000 + startval - delays;
		while(wait < SysTick->VAL)
		{

		}
	}
  else
	{
		wait = startval - delays;
		while(wait < SysTick->VAL && HAL_GetTick() == tickn)
		{

		}
	}
}

// 初始化GPIO
void M2716_GPIO_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();

    // 配置地址线为输出模式
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 |
                          GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 |
                          GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(M2716_ADDR_PORT, &GPIO_InitStruct);

    // 配置数据线为双向模式，读写时可切换
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 |
                          GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(M2716_DATA_PORT, &GPIO_InitStruct);

    // 配置控制信号引脚为输出模式
    GPIO_InitStruct.Pin = M2716_GP_PIN | M2716_EP_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    // 初始时使能信号置高
    HAL_GPIO_WritePin(M2716_GP_PORT, M2716_GP_PIN, GPIO_PIN_SET);
    HAL_GPIO_WritePin(M2716_EP_PORT, M2716_EP_PIN, GPIO_PIN_RESET);
    //HAL_GPIO_WritePin(M2716_VPP_CTRL_PORT, M2716_VPP_CTRL_PIN, GPIO_PIN_RESET); // 初始为5V
	VPP_5V 
}

// 设置数据线为输出模式
void SetDataPortOutput(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 |
                          GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(M2716_DATA_PORT, &GPIO_InitStruct);
}

// 设置数据线为输入模式
void SetDataPortInput(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 |
                          GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(M2716_DATA_PORT, &GPIO_InitStruct);
}

//连续写入
void M2716_3_Write(uint16_t addrsta,uint8_t data,uint16_t size,uint16_t delayus)
{
	uint16_t i = 0;
	uint32_t temp = 0;
	
	if(size<1)
	{
		return;
	}
	
	if(addrsta>0x7FF)
	{
		return;
	}

	temp=addrsta+size-1;

	if(temp>0x7FF)
		size = 0x7FF - addrsta;
	
	// 使能编程电压
	VPP_25V;
	HAL_Delay(100);
	
	for(i=0;i<size;i++)
	{
		
			HAL_GPIO_WritePin(M2716_GP_PORT, M2716_GP_PIN, GPIO_PIN_SET);    // GP置为无效，不让芯片输出数据（可用宏替换）
			M_Delay_us(1); 												     // >120ns->1us
			SetDataPortOutput(); 										     // 设置数据线为输出模式
			M2716_ADDR_PORT->ODR = addrsta;								     // 设置地址
			M2716_DATA_PORT->ODR = data;									 // 设置要写入的数据
			M_Delay_us(3);  												 // 满足tA/QVPH >2μs
		
			HAL_GPIO_WritePin(M2716_EP_PORT, M2716_EP_PIN, GPIO_PIN_SET); 	 //	脉冲
			M_Delay_us(delayus);											 // 保持DATA IN时间
			HAL_GPIO_WritePin(M2716_EP_PORT, M2716_EP_PIN, GPIO_PIN_RESET);
			M_Delay_us(3);  												 // 满足tPLAX >2μs
			HAL_GPIO_WritePin(M2716_GP_PORT, M2716_GP_PIN, GPIO_PIN_RESET);
			M_Delay_us(1); 
																			 //	验证部分
			HAL_GPIO_WritePin(M2716_EP_PORT, M2716_EP_PIN, GPIO_PIN_RESET);
			M_Delay_us(1);
			addrsta++;
	}
	HAL_Delay(1);  
  VPP_5V;// 恢复电压
}


//对 M2716 芯片的连续多字节读取，并将每个读取到的数据通过串口发送出去。
uint8_t M_4_Char[2048];
//addrsta：起始地址
//size：要读取的数据长度（字节数）
uint16_t M2716_4_Read(uint16_t addrsta,uint16_t size)
{
	uint16_t i = 0;
	//边界检查与修正：如果请求读取的长度超出芯片范围，则自动修正为最大可读长度。
	uint32_t temp = 0;
	temp+=size;
	if(temp>0x7FF) //2048
		size = 0x7FF - addrsta;
	//读取数据前，必须把数据线配置为输入
	SetDataPortInput();
	//循环读取每个字节
	for(i=0;i<size;i++)
	{
		M2716_ADDR_PORT->ODR = addrsta;									// 设置当前要读的地址
		SetDataPortInput();												// 确保设置数据线为输入模式
		HAL_GPIO_WritePin(M2716_EP_PORT, M2716_EP_PIN, GPIO_PIN_RESET);	// 使能片选
		HAL_GPIO_WritePin(M2716_GP_PORT, M2716_GP_PIN, GPIO_PIN_RESET);	// 拉低编程使能信号，保证芯片处于可读状态
		M_Delay_us(2);													// 等待信号稳定
		M_4_Char[i] = (uint8_t)(M2716_DATA_PORT->IDR & 0xFF);			// 读取数据
		M2716_UART_Send(0x04,addrsta,M_4_Char[i],0x00);					// 通过串口发送地址和数据（涉及团队合作沟通）
		addrsta++;														// 递增地址，准备读取下一个字节
	}
	return i;															// 返回实际读取的字节数
	